//input layout
#include "vertexDefs.hlsli"
//constant buffers & global texture resources
#include "sharedpool.hlsli"
//utility functtions to calculate light intensity
#include "lightHelper.hlsli"

cbuffer localPerObject
{
	float4x4 gWorld;
};

Texture2D gDiffuseMap;
Texture2D gNormalMap;
Texture2D gSpecularMap;

cbuffer Material
{
	float4 matDiffuse;
	float4 matSpecular;
};

VS_PN_Out VS_PN( Vertex_PN vIn)
{
	VS_PN_Out vOut;
	float4 posW = mul(float4(vIn.position, 1.0f), gWorld);

	vOut.positionH = mul(posW, mul(gView, gProjection));
	vOut.positionW = posW.xyz;
	vOut.normalW = mul(float4(vIn.normal, 0.0f), gWorld).xyz;

	return vOut;
}

float4 PS_PN(PS_PN_In pIn) : SV_Target
{
	float3 normalW = normalize(pIn.normalW);
	SurfaceInfo s = { pIn.positionW, normalW, matDiffuse, matSpecular};
	float3 litColor = float3(0, 0, 0);
	for(int i = 0; i < numLights; ++i)
	{
		if(gLights[i].type == DIRECTED_LIGHT)
			litColor += directionalLight(s, gLights[i], gEyePosW);
		else if(gLights[i].type == POINT_LIGHT)
			litColor += pointLight(s, gLights[i], gEyePosW)
		else 
			litColor += spotLight(s, gLights[i], gEyePosW);
	}

	return float4(liColor, matDiffuse.a);
}

VS_PNT_Out VS_PNT(Vertex_PNT vIn)
{
	VS_PNT_Out vOut;
	float4 posW = mul(float4(vIn.position, 1.0f), gWorld);

	vOut.positionH = mul(posW, mul(gView, gProjection));
	vOut.positionW = posW.xyz;
	vOut.normalW = mul(float4(vIn.normal, 0.0f), gWorld).xyz;
	vOut.texCoord = vIn.texCoord;

	return vOut;
}

float4 PS_PNT(PS_PNT_In pIn) : SV_Target
{
	float4 diffuse = gDiffuseMap.Sample( gBilinearSampler, pIn.texCoord);

	float3 normalW = normalize(pIn.normalW);
	SurfaceInfo s = { pIn.positionW, normalW, diffuse, matSpecular};
	float3 litColor = float3(0, 0, 0);
	for(int i = 0; i < numLights; ++i)
	{
		if(gLights[i].type == DIRECTED_LIGHT)
			litColor += directionalLight(s, gLights[i], gEyePosW);
		else if(gLights[i].type == POINT_LIGHT)
			litColor += pointLight(s, gLights[i], gEyePosW)
		else 
			litColor += spotLight(s, gLights[i], gEyePosW);
	}

	return float4(liColor, diffuse.a);
}

float4 PS_PNT_withSpecular(PS_PNT_In pIn) : SV_Target
{
	float4 diffuse = gDiffuseMap.Sample( gBilinearSampler, pIn.texCoord);
	float4 spec = gSpecularMap.Sample(gBilinearSampler, pIn.texCoord);

	spec.a *= 256.0f;

	float3 normalW = normalize(pIn.normalW);
	SurfaceInfo s = { pIn.positionW, normalW, diffuse, spec};
	float3 litColor = float3(0, 0, 0);
	for(int i = 0; i < numLights; ++i)
	{
		if(gLights[i].type == DIRECTED_LIGHT)
			litColor += directionalLight(s, gLights[i], gEyePosW);
		else if(gLights[i].type == POINT_LIGHT)
			litColor += pointLight(s, gLights[i], gEyePosW)
		else 
			litColor += spotLight(s, gLights[i], gEyePosW);
	}

	return float4(liColor, diffuse.a);
}

VS_PNTT_Out VS_PNTT(Vertex_PNTT vIn)
{
	VS_PNTT_Out vOut;
	float4 posW = mul(float4(vIn.position, 1.0f), gWorld);

	vOut.positionH = mul(posW, mul(gView, gProjection));
	vOut.positionW = posW.xyz;
	vOut.normalW = mul(float4(vIn.normal, 0.0f), gWorld).xyz;
	vOut.tangentW = mul(float4(vIn.tangent, 0.0f), gWorld).xyz;
	vOut.texCoord = vIn.texCoord;

	return vOut;
}

float4 PS_PNTT(PS_PNTT_In pIn) : SV_Target
{
	float4 diffuse = gDiffuseMap.Sample(gBilinearSampler, pIn.texCoord);
	clip(diffuse.a - 0.15f);

	float3 normalT = gNormalMap.Sample(gBilinearSampler, pIn.texCoord);
	normalT = 2.0f*normalT - 1.0f;

	float3 N = normalize(pIn.normalW);
	float3 T = normalize(pIn.tangentW - dot(pIn.tangentW, N)*N);
	float3 B = cross(N,T);
	float3x3 TBN = float3x3(T, B, N);
	float3 bumpedNormalW = normalize(mul(normalT, TBN));

	SurfaceInfo s = {pIn.positionW, bumpedNormalW, diffuse, matSpecular};
	float3 litColor = float3(0, 0, 0);
	for(int i = 0; i < numLights; ++i)
	{
		if(gLights[i].type == DIRECTED_LIGHT)
			litColor += directionalLight(s, gLights[i], gEyePosW);
		else if(gLights[i].type == POINT_LIGHT)
			litColor += pointLight(s, gLights[i], gEyePosW)
		else 
			litColor += spotLight(s, gLights[i], gEyePosW);
	}

	return float4(liColor, diffuse.a);
}

float4 PS_PNTT_withSpecular(PS_PNTT_In pIn) : SV_Target
{
	float4 diffuse = gDiffuseMap.Sample(gBilinearSampler, pIn.texCoord);
	float4 spec = gSpecularMap.Sample(gBilinearSampler, pIn.texCoord);

	spec.a *= 256.0f;

	clip(diffuse.a - 0.15f);

	float3 normalT = gNormalMap.Sample(gBilinearSampler, pIn.texCoord);
	normalT = 2.0f*normalT - 1.0f;

	float3 N = normalize(pIn.normalW);
	float3 T = normalize(pIn.tangentW - dot(pIn.tangentW, N)*N);
	float3 B = cross(N,T);
	float3x3 TBN = float3x3(T, B, N);
	float3 bumpedNormalW = normalize(mul(normalT, TBN));

	SurfaceInfo s = {pIn.positionW, bumpedNormalW, diffuse, spec};
	float3 litColor = float3(0, 0, 0);
	for(int i = 0; i < numLights; ++i)
	{
		if(gLights[i].type == DIRECTED_LIGHT)
			litColor += directionalLight(s, gLights[i], gEyePosW);
		else if(gLights[i].type == POINT_LIGHT)
			litColor += pointLight(s, gLights[i], gEyePosW)
		else 
			litColor += spotLight(s, gLights[i], gEyePosW);
	}

	return float4(liColor, diffuse.a);
}

technique10 PN
{
	pass p0
	{
		SetVertexShader(CompileShader(vs_4_1, VS_PN()));
		SetGeometryShader(NULL);
		SetPixelShader(CompileShader(ps_4_1, PS_PN()));
	}
}

technique10 PNT_withoutSpecularMap
{
	pass p0
	{
		SetVertexShader(CompileShader(vs_4_1, VS_PNT()));
		SetGeometryShader(NULL);
		SetPixelShader(CompileShader(ps_4_1, PS_PNT()));
	}
}

technique10 PNT_withSpecularMap
{
	pass p0
	{
		SetVertexShader(CompileShader(vs_4_1, VS_PNT()));
		SetGeometryShader(NULL);
		SetPixelShader(CompileShader(ps_4_1, PS_PNT_withSpecular()));
	}
}

technique10 PNTT_withoutSpecularMap
{
	pass p0
	{
		SetVertexShader(CompileShader(vs_4_1, VS_PNTT()));
		SetGeometryShader(NULL);
		SetPixelShader(CompileShader(ps_4_1, PS_PNTT()));
	}
}

technique10 PNTT_withSpecularMap
{
	pass p0
	{
		SetVertexShader(CompileShader(vs_4_1, VS_PNTT()));
		SetGeometryShader(NULL);
		SetPixelShader(CompileShader(ps_4_1, PS_PNTT_withSpecular()));
	}
}